package com.hvgroup.modules.sanic.service.impl.chat.chat;


import com.alibaba.fastjson.JSON;
import com.hvgroup.modules.sanic.domain.po.QaMessage;
import com.hvgroup.modules.sanic.domain.po.QaSession;
import com.hvgroup.modules.sanic.domain.qo.QaQuestionQuery;
import com.hvgroup.modules.sanic.repository.LlmAppRepository;
import com.hvgroup.modules.sanic.repository.QaMessageRepository;
import com.hvgroup.modules.sanic.repository.QaSessionRepository;
import com.hvgroup.modules.sanic.service.impl.chat.EventData;
import com.hvgroup.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Dify 流式回答节点处理器
 * 负责处理 Dify 平台“节点完成”事件，业务数据落库与内容结构化
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class DifyAnswerHandler extends DifyHandler implements EventHandler {

    private final QaSessionRepository qaSessionRepository;
    private final QaMessageRepository qaMessageRepository;
    //    private final AppsRepository appsRepository;
    private final LlmAppRepository llmAppRepository;

    /**
     * 事件类型判定：只处理“节点完成”类型事件
     */
    @Override
    public boolean supports(Map<String, Object> eventMap) {
        try {
            String event = processStr().apply(eventMap, dify.getEvent());
            return dify.getNodeFinish().getKey().equals(event);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return false;
        }
    }

    /**
     * 流递进+业务落库：处理命中事件，完成数据存储与输出
     */
    @Override
    @Transactional
    public synchronized EventData handle(Map<String, Object> eventMap, EventData preData) {
        // 1. 会话查找或新建
        QaQuestionQuery query = preData.getBusData();
        QaSession qaSession = Optional.ofNullable(query.getChatId())
                .flatMap(qaSessionRepository::findById)
                .orElseGet(() -> {
                    QaSession tmp = new QaSession();
                    tmp.setConversationId(StringUtils.defaultIfEmpty(query.getConversationId(), (String) eventMap.get("conversation_id")));
                    tmp.setTitle(preData.getText());
                    tmp.setEnable(true);
                    tmp.setUserId(query.getUserId());
                    tmp.setAppId(query.getAppId());
                    llmAppRepository.findFirstByAppId(query.getAppId())
                            .ifPresent(app ->{
                                tmp.setAppId(app.getAppId());
                                tmp.setAppName(app.getName());
                            });
                    query.setChatId(tmp.getChatId());
                    return qaSessionRepository.save(tmp);
                });
        qaSession.setUpdateTime(new Timestamp(System.currentTimeMillis()));
        qaSession.setUserId(query.getUserId());
        qaSessionRepository.save(qaSession);

        // 2. 消息存储
        QaMessage qaMessage = new QaMessage();
        qaMessage.setChatId(qaSession.getChatId());
        qaMessage.setQuestion(preData.getText());
        qaMessage.setQaType(query.getQaType());
        qaMessage.setMessageId((String) eventMap.get("message_id"));
        qaMessage.setTaskId((String) eventMap.get("task_id"));
//        qaMessage.setFileKey(fileKey);
        qaMessage.setFileUrl(query.getFileUrl());
        qaMessage.setFileSize(query.getFileSize());
//        qaMessage.setCreateBy();

        // 3. 特殊标签处理
        String think = "";
        String answer = StringUtils.defaultIfEmpty(processStr().apply(eventMap, dify.getNodeFinish().getValue()), "")
                .replaceAll("dify_0_t02|dify_1_t02|dify_0_t04|dify_2_t04", "");




        if (StringUtils.isNotEmpty(answer) && answer.contains("<think>")) {
            Pattern pattern = Pattern.compile("<think>[\\s\\S]*?</think>", Pattern.DOTALL);
            Matcher matcher = pattern.matcher(answer);
            if (matcher.find()) {
                think = matcher.group(0).replaceAll("\n", ""); // 匹配中间内容; 前端展示think不能存在\n
                answer = think + "\n\n" + answer.replaceAll("<think>[\\s\\S]*?</think>", "");
            }
            qaMessage.setModelThink(StringUtils.defaultString(think, "").replaceAll("<think>|</think>", ""));
        } else if (StringUtils.isNotEmpty(answer) && answer.contains("</details>")) {
            Pattern pattern = Pattern.compile("<details[\\s\\S]*?</details>", Pattern.DOTALL);
            Matcher matcher = pattern.matcher(answer);
            if (matcher.find()) {
                think = matcher.group(0).replaceAll("\n", ""); // 匹配中间内容; 前端展示think不能存在\n
                answer = think + "\n\n" + answer.replaceAll("<details[\\s\\S]*?</details>", "");
            }
            qaMessage.setModelThink(StringUtils.defaultString(think, ""));
        }

        // 4. 生成结构化 JSON 内容，落库
        Map<String, Object> map = buildResultJson(answer);

        qaMessage.setFileKey(preData.getBusData().getFileKey());
        qaMessage.setModelAnswer(JSON.toJSONString(map).replace("Thinking...", "Finished."));
        qaMessage.setRating(0);
        qaMessage.setTotalToken(processStr().apply(eventMap, dify.getTokens()));
        qaMessage.setThinkTime(System.currentTimeMillis() - preData.getRequestTimestamp());
        qaMessageRepository.save(qaMessage);

        map.put("feadId", qaMessage.getId());
        map.put("chatId", qaMessage.getChatId());
        map.put("conversationId", qaSession.getConversationId());
        map.put("thinkTime", qaMessage.getThinkTime());
        map.put("dataType", "t02");

        // 5. 返回新的 EventData（递进 step + 结构化业务文本）
        return EventData.buildNext(preData)
                .apply(EventData.builder().text(JSON.toJSONString(map)));
    }

    /**
     * 构建SSE或前端用业务JSON数据（带内容字符串）
     */
    Map<String, Object> buildResultJson(String content) {
        Map<String, Object> result = new HashMap<>();
        Map<String, Object> data = new HashMap<>();
        data.put("messageType", "continue");
        data.put("content", "> " + content);
        result.put("data", data);
        result.put("dataType", "t02");
        return result;
    }

}
